/* model */
import { 
  BaseSelectUserComponentNameEnum, 
  BaseSelectUserTree, 
  SelectUserComponentDepartment, 
  SelectUserComponentRole, 
  SelectUserComponentServiceProvider 
} from '@src/component/common/BaseSelectUser/model'
/* hooks */
import { useBaseSelectUserOptions, useSelectUserChecked, useSelectUserCheckedItemList } from '@src/component/common/BaseSelectUser/hooks'
import { useBaseSelectUserStoreIsFilterVisible } from '@src/component/common/BaseSelectUser/store'
/* scss */
import '@src/component/common/BaseSelectUser/components/Tree/index.scss'
/* vue */
// @ts-ignore
import { ComponentInstance, ComponentRenderProxy, computed, defineComponent, PropType, ref } from 'vue'
import { CommonComponentInstance } from '@model/VC'
import { CreateElement } from 'vue'
/* types */
import { BaseSelectUserSelectedItemType } from '@src/component/common/BaseSelectUser/types'
/* util */
import { transformServerTreeToComponentTree } from '@src/component/common/BaseSelectUser/components/Tree/util'
import { isDisabledSelectItem, isRoleSelectType, transformRoleName } from '@src/component/common/BaseSelectUser/util'
import { findComponentsDownward } from '@src/util/assist'
import Log from '@src/util/log'
import { isFalse, isFalsy } from '@src/util/type'
import { randomString } from 'pub-bbx-utils'
import { getIsOpenData } from '@src/util/platform'
import { dispatch } from '@src/util/emitter'
import { computedStrLen } from '@src/util/lang/string'
import { debounce } from 'lodash'

/* component */
import { SelectContentEmitEventNameEnum } from '@src/component/common/BaseSelectUser/components/SelectContent'

export type BaseSelectUserTreeProps = {
  currentNodeKey: string;
  defaultExpandedKeys: string[];
  defaultCheckedKeys: string[];
  isMulti: boolean;
  data: SelectUserComponentDepartment[] | SelectUserComponentRole[] | SelectUserComponentServiceProvider[];
  showCheckbox: boolean;
}

export interface BaseSelectUserTreeSetupState {
  
}

export enum BaseSelectUserTreeEmitEventNameEnum {
  Input = 'input',
  Click = 'click',
  Check = 'check',
}

export type BaseSelectUserTreeInstance = ComponentInstance & BaseSelectUserTreeSetupState
export type BaseSelectUserTreeVM = ComponentRenderProxy<BaseSelectUserTreeProps> & CommonComponentInstance & BaseSelectUserTreeInstance

export default defineComponent({
  name: BaseSelectUserComponentNameEnum.BaseSelectUserTree,
  emits: [
    BaseSelectUserTreeEmitEventNameEnum.Input,
    BaseSelectUserTreeEmitEventNameEnum.Click,
    BaseSelectUserTreeEmitEventNameEnum.Check
  ],
  props: {
    currentNodeKey: {
      type: String as PropType<string>,
      default: ''
    },
    defaultExpandedKeys: {
      type: Array as PropType<string[]>,
      default: () => []
    },
    defaultCheckedKeys: {
      type: Array as PropType<string[]>,
      default: () => []
    },
    /* 数据 */
    data: {
      type: Array as PropType<SelectUserComponentDepartment[] | SelectUserComponentRole[] | SelectUserComponentServiceProvider[]>,
      default: () => []
    },
    /* 是否为多选状态 */
    isMulti: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    showCheckbox: {
      type: Boolean as PropType<boolean>,
      default: false
    }
  },
  setup(props: BaseSelectUserTreeProps, { emit }) {
    
    const BaseSelectUserTreeRef = ref('BaseSelectUserTree')
    
    const { checkIsChecked, checkIsDisabled, selectLimitMessage } = useSelectUserChecked()
    const { checkedDepartmentItemList, addCheckedItem, removeCheckedItem } = useSelectUserCheckedItemList()
    const { isFilterVisible, setIsFilterVisible } = useBaseSelectUserStoreIsFilterVisible()
    
    // 组件配置
    const { isHideUser, isDepartmentSingle, isOnlyShowBusinessServiceCloudRole, isCheckStrictly } = useBaseSelectUserOptions()
    
    const isInitLoad = ref(false)
    const componentKey = ref(randomString())
    
    const treeData = computed(() => {
      return transformServerTreeToComponentTree(props.data)
    })
    
    const clearFilterPopper = () => {
      setIsFilterVisible(false)
    }
    
    const onCheckChangeHandler = (data: BaseSelectUserTree) => {
      emit(BaseSelectUserTreeEmitEventNameEnum.Check, data)
    }
    
    return {
      isInitLoad,
      isHideUser,
      isDepartmentSingle,
      isFilterVisible,
      treeData,
      componentKey,
      BaseSelectUserTreeRef,
      isOnlyShowBusinessServiceCloudRole,
      isCheckStrictly,
      
      selectLimitMessage,
      
      removeCheckedItem,
      addCheckedItem,
      checkedDepartmentItemList,
      
      checkIsChecked,
      checkIsDisabled,
      
      onCheckChangeHandler,
      clearFilterPopper
      
    }
    
  },
  watch: {
    data: {
      immediate: true,
      handler() {
        this.isInitLoad = true
        
        setTimeout(() => {
          this.setCurrentNodeHighlight()
        }, 300)
        
      }
    }
  },
  methods: {
    clearCurrentNodeHighlight() {
      try {
        
        const elTreeNodeComponents = this.getAllElTreeNodeComponent()
        
        elTreeNodeComponents.forEach((item: Record<string, any>) => {
          item.node.isCurrent = false
        })
        
      } catch (error) {
        Log.error(error, this.clearCurrentNodeHighlight.name)
      }
    },
    getAttributes() {
      return {
        key: this.componentKey,
        props: {
          // 配置选项
          props: {
            // 指定子树为节点对象的某个属性值
            children: 'tagChildren'
          }
        }
      }
    },
    getAllElTreeNodeComponent() {
      return findComponentsDownward(this, 'ElTreeNode')
    },
    onCheckboxInputHandler(data: BaseSelectUserTree) {
      
      const isChecked = this.checkIsChecked(data)
      const isDisabled = this.checkIsDisabled(data)
      
      if (this.isFilterVisible) {
        this.clearFilterPopper()
        return
      }

      // 只做了无选择上限的。
      if(data.tagChildren?.length && !this.isCheckStrictly) {
        data.tagChildren.forEach((item: BaseSelectUserTree) => {
          this.depChildCheckbox(item, !isChecked);
        })
      }

      if (isChecked) {
        this.removeCheckedItem(data as BaseSelectUserSelectedItemType)
        return
      }
      
      if (isDisabled) {
        this.selectLimitMessage()
        return
      }
      
      // 非只展示服务云云 且 为角色，则添加 产品线前缀
      if (isFalsy(this.isOnlyShowBusinessServiceCloudRole) && isRoleSelectType(data as BaseSelectUserSelectedItemType)) {
        this.addCheckedItem(transformRoleName(data as BaseSelectUserSelectedItemType))
        return 
      }
      
      this.addCheckedItem(data as BaseSelectUserSelectedItemType)

    },
    depChildCheckbox(data: BaseSelectUserTree, bool: Boolean) {
      const isChecked = this.checkIsChecked(data)
      const isDisabled = this.checkIsDisabled(data)

      if (isDisabled) {
        debounce(() => {
          this.selectLimitMessage();
        }, 500)
        return
      }

      if(bool && !isChecked) {
        this.addCheckedItem(data as BaseSelectUserSelectedItemType)
      }
      if(!bool) {
        this.removeCheckedItem(data as BaseSelectUserSelectedItemType)
      }

      data.tagChildren.forEach((x: BaseSelectUserTree) => {
        this.depChildCheckbox(x, bool);
      })
    },
    onCheckboxClickHandler(event: Event) {
      event.stopPropagation()
    },
    onNodeClickHandler(data: BaseSelectUserTree) {
      
      // 如果此节点仅仅是用来展示的 则不做任何操作
      if (data.isOnlyDisplay) {
        return
      }
      
      if (this.isInitLoad) {
        
        this.$nextTick(() => {
          this.setCurrentNodeHighlight()
        })
        
        this.isInitLoad = false
        
      }
      
      // 部门单选
      if (this.isDepartmentSingle) {
        
        // 单选 如果之前有数据 则删除
        if(this.checkedDepartmentItemList.length){
          this.removeCheckedItem(this.checkedDepartmentItemList[0] as BaseSelectUserSelectedItemType)
        }
        
        // 添加选中新数据
        this.addCheckedItem(data as BaseSelectUserSelectedItemType)
        
        // 支持由自定义组件 发出事件
        dispatch.call(
          this,
          BaseSelectUserComponentNameEnum.BaseSelectUserSelectContent, 
          SelectContentEmitEventNameEnum.Confirm
        )
        
        return
      }
      
      // 隐藏用户
      if (this.isHideUser) {
        this.onCheckboxInputHandler(data)
        return
      }
      
      // 显示筛选框，则关闭筛选框
      if (this.isFilterVisible) {
        this.clearFilterPopper()
        return
      }
      
      // 分发事件
      this.$emit(BaseSelectUserTreeEmitEventNameEnum.Click, data)
      
    },
    onResize() {
      this.componentKey = randomString()
    },
    nodeRender(h: CreateElement, content: { data: BaseSelectUserTree }) {
      
      const data = content.data
      const count = data?.userCount || 0

      // 如果此节点仅仅是用来展示的 则不做任何操作，隐藏多选
      const isOnlyDisplay = Boolean(data.isOnlyDisplay)
      
      const isChecked = this.checkIsChecked(data)
      const isDisabled = isDisabledSelectItem(data as BaseSelectUserSelectedItemType)
      const isNotDisabled = isFalse(isDisabled)
      
      const defaultLeftTreePanelWidth = 270
      const defaultLeftTreePanelItemOtherWidth = 140
      const singleTextWidth = 7 // 英文字母数字长度计算
      
      const clientWidth = this.$el?.clientWidth || defaultLeftTreePanelWidth
      const nameWidth = clientWidth - defaultLeftTreePanelItemOtherWidth
      const nameLength = Math.round(nameWidth / singleTextWidth)
      
      const name = computedStrLen(data.name)> nameLength ? data.name.slice(0, nameLength) + '...' : data.name
      
      /** 
       * @description 是否显示多选框
       * 1. 属性 showCheckbox 为 true
       * 2. 节点不是禁用的
       * 3. 节点不是仅仅用来展示的
      */
      const isShowCheckbox = this.showCheckbox && isNotDisabled && isFalse(isOnlyDisplay)

      const checkbox = isShowCheckbox && (
        <el-checkbox
          value={isChecked}
          onInput={() => this.onCheckboxInputHandler(data)}
          nativeOnClick={this.onCheckboxClickHandler}
        >
        </el-checkbox>
      )
      
      const isOpenData = getIsOpenData()
      const tagNameEle = (<span class="base-select-user-tree-item__name">
        {isOpenData ? (
          <open-data type="departmentName" openid={data.name} />
        ) : (
          name
        )}
      </span>)
      const contentElement = (
        <span>
          {/* 部门有...用tooltip显示全 */}
          {data.name.length > nameLength && (<el-tooltip placement="top" popper-class="base-user-label-tooltip-popper">
            <div slot="content">
              <span class="base-select-user-tree-item__name">
                {isOpenData ? (
                  <open-data type="departmentName" openid={data.name} />
                ) : (
                  data.name
                )}
              </span>
            </div>
            { tagNameEle }
          </el-tooltip>)}

          { data.name.length <= nameLength && tagNameEle } 

          {(
            <span class="base-select-user-tree-item__count">
              （{ count }）
            </span>
          )}
        </span>
      )
      
      return (
        <div class="base-select-user-tree-item" onClick={(event: Event) => this.treeItemClickHandler(event, data)}>
          { checkbox }
          { contentElement }
        </div>
      )
    },
    setCurrentNodeHighlight() {
      try {
        
        const elTreeNodeComponents = this.getAllElTreeNodeComponent()
        
        elTreeNodeComponents.forEach((item: Record<string, any>) => {
          let isCurrentNode = item?.node?.data?.id == this.currentNodeKey
          item.node.isCurrent = isCurrentNode
        })
        
      } catch (error) {
        Log.error(error, this.setCurrentNodeHighlight.name)
      }
    },
    treeItemClickHandler(event: Event, data: BaseSelectUserTree) {
      
      // 如果此节点仅仅是用来展示的 则触发展开收起事件
      if (data.isOnlyDisplay) {
        this.treeItemClickToggleHandler(event, data)
      }
      
    },
    treeItemClickToggleHandler(event: Event, data: BaseSelectUserTree) {
      
      const target = event.target as HTMLElement
      const elTreeComponent = this.$refs[this.BaseSelectUserTreeRef] as Record<string, any>
      const elTreeNodeComponents = elTreeComponent?.$children || [] as Record<string, any>[]
      
      elTreeNodeComponents.forEach((elTreeNodeComponent: Record<string, any>) => {
        
        const elTreeNodeComponentEl = elTreeNodeComponent?.$el as HTMLElement
        
        if (elTreeNodeComponentEl && elTreeNodeComponentEl.contains(target)) {
          elTreeNodeComponent.handleExpandIconClick(event)
          return false
        }
        
      })
      
    }
  },
  render(h: CreateElement) {
    
    const attrs = this.getAttributes()
    
    return (
      <div class={BaseSelectUserComponentNameEnum.BaseSelectUserTree} v-resize-width={this.onResize}>
        <el-tree
          {...attrs}
          ref={this.BaseSelectUserTreeRef}
          /* 在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false */
          check-strictly
          /* 每个树节点用来作为唯一标识的属性，整棵树应该是唯一的 */
          node-key="id"
          /* 是否高亮当前选中节点，默认值是 false。 */
          highlight-current
          /* 是否在点击节点的时候展开或者收缩节点， 默认值为 true，如果为 false，则只有点箭头图标的时候才会展开或者收缩节点。 */
          expand-on-click-node={false}
          /* 	是否默认展开所有节点 */
          default-expand-all={false}
          /* 展示数据 */
          data={this.treeData}
          /* 当前选中的节点 */
          current-node-key={this.currentNodeKey}
          /* 默认展开的节点的 key 的数组 */
          default-expanded-keys={this.defaultExpandedKeys}
          /* 默认勾选的节点的 key 的数组 */
          default-checked-keys={this.defaultCheckedKeys}
          /* 节点被点击时的回调 */
          onNode-click={this.onNodeClickHandler}
          /* 节点选中状态发生变化时的回调 */
          onCheck-change={this.onCheckChangeHandler}
          /* 树节点的内容区的渲染 Function */
          render-content={this.nodeRender}
        >
        </el-tree>
      </div>
    )
  }
})
